import django_excel
from rest_framework.decorators import action


class HasRolesMixin:
    '''
    判定是否为拥有角色组
    '''

    def has_role(self, role_name):
        if self.request.user.is_anonymous:
            return False
        roles = self.request.user.groups.all().values_list('name').first()
        if role_name in roles:
            return True


class ExportExcelMixin:
    '''
    导入导出表格
    export_fields:一定要与serializer
    '''
    export_fields = None
    table_headers = None
    export_serializer_class = None

    @action(methods=['GET'], detail=False, permission_classes=[])
    def export(self, request, *args, **kwargs):
        pass

    def perform_export(self, file_name='导出测试'):
        assert self.export_fields, (
                "'%s' 请配置对应的导出模板字段。"
                % self.__class__.__name__
        )
        queryset = self.get_queryset()
        serializer = self.export_serializer_class(queryset, many=True)

        self.table_headers.insert(0, '序号')
        wdata = [self.table_headers]  # 表格首行内容

        for index, obj in enumerate(serializer.data, start=1):
            row = [obj[field] for field in self.export_fields]
            row.insert(0, index)
            wdata.append(row)

        sheet = django_excel.pe.Sheet(wdata)

        return django_excel.make_response(pyexcel_instance=sheet, file_name=file_name, file_type="xlsx")


class ImportExcelMixin:
    import_fields = None
    table_headers = None
    import_serializer_class = None

    @action(methods=['POST'], detail=False, url_path='import')
    def import_(self, request, *args, **kwargs):
        pass

    def perform_import(self):
        assert self.import_fields, (
                "'%s' 请配置对应的导入模板字段。"
                % self.__class__.__name__
        )
        pass


class ImportAndExportExcelMixin(ImportExcelMixin, ExportExcelMixin):
    pass


class BaseExcelImport():
    """
    django 处理excel数据导入
    将excel内容写入数据库时，需要注意以下两点
        1、默认唯一值是name，如果你的model不是时，需要重写get_instance方法
        2、默认删除id列内容，如果还有特殊处理，需要重写deal_special_field方法
            deal_special_field重新注意点
                a、需要同时删除id列时，加入父类id处理或者调用父类+自定义内容
                b、不需要删除id列时，完全重写
    """

    def __init__(self, serializer_class, model, sheet):
        """
        初始化
        :param serializer_class: model序化类
        :param model: 待操作model类名称
        :param sheet: 导入excel内容
        """
        self.serializer_class = serializer_class
        self.model = model
        self.sheet = sheet

    def save_excel_to_db(self):
        self.deal_excel()
        self.save_data()

    def deal_excel(self):
        """
        处理输入的excel并返回其内容列表
        :return: [{},{}]
        """
        self.data_list = self.deal_row_data()
        return self.data_list

    def deal_row_data(self):
        """
        处理导入excel中每一个行内容
        :return:
        """
        sheet = self.sheet
        header = sheet.row[0]
        attr_list = self.get_attr_map(header)
        post_data_list = []
        for idx in range(1, sheet.number_of_rows()):
            rdata = sheet.row[idx]
            tmp = dict(zip(attr_list, rdata))
            post_data_list.append(tmp)

        return post_data_list

    def get_attr_map(self, header):
        """
        建立表头和model字段对应关系
        :param header:
        :return:
        """
        field_dict = {field.verbose_name: field.name for field in self.model._meta.fields}
        attr_list = []
        for idx, head in enumerate(header):
            attr_list.append(field_dict[head])

        return attr_list

    def save_data(self):
        # 保存到数据库
        for data in self.data_list:
            self.in_obj_data = data
            # self.deal_special_field()

            obj = self.get_instance()
            if obj:
                # update
                ser = self.serializer_class(obj, data=data)
            else:
                # create
                ser = self.serializer_class(data=data)
            ser.is_valid(raise_exception=True)
            ser.save()

    def deal_special_field(self):
        """
        处理特殊 字段内容，如删除excel中主键内容，如id，防止输入主键内容意外覆盖正常内容
        :param data:
        :return:
        """
        master_key = "id"  # 删除主键列内容
        del self.in_obj_data[master_key]

    def get_instance(self):
        """
        根据唯一字段获取对应对象
        :return:
        """
        obj = None
        try:
            obj = self.model.objects.get(name=self.in_obj_data["name"])
        except:
            pass

        return obj


class ReportExcelImport(BaseExcelImport):
    def get_instance(self):
        obj = None
        try:
            obj = self.model.objects.get(number=self.in_obj_data["number"])
        except:
            pass

        return obj
